﻿using AppWebApi.Authorization;
using Microsoft.Extensions.Caching.Memory;
using Modules;
using Modules.App;
using PmSoft.ApplicationContext;
using PmSoft.Entity;
using PmSoft.Jiguang;
using PmSoft.Utilities;

namespace AppWebApi.Mvc
{
    /// <summary>
    /// APP用户状态信息供应器
    /// </summary>
    public class CurrentUserUserStateProvider : IApplicationContextStateProvider
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IJiguangService jiguangService;
        private readonly IMemoryCache memoryCache;
        private readonly AppDeviceService appDeviceService;
        public CurrentUserUserStateProvider(IHttpContextAccessor _httpContextAccessor, JiguangService jiguangService, IMemoryCache memoryCache, AppDeviceService appDeviceService)
        {
            this._httpContextAccessor = _httpContextAccessor;
            this.jiguangService = jiguangService;
            this.memoryCache = memoryCache;
            this.appDeviceService = appDeviceService;
        }

        public string Name => "CurrentUser";

        IUser? _currentUserInfo;

        public Func<ApplicationContext, T?> Get<T>()
        {
            return context =>
            {
                if (_currentUserInfo != null)
                    return (T)_currentUserInfo;

                var authorizationVal = _httpContextAccessor.HttpContext?.Request.Headers.FirstOrDefault(o => o.Key == "Authorization");
                var phoneUuid = _httpContextAccessor.HttpContext?.Request.Headers.FirstOrDefault(o => o.Key == "phoneUUid");
                if (phoneUuid == null)
                    throw new ArgumentNullException(nameof(phoneUuid));
                if (phoneUuid.Value.Value.ToString() == "")
                {
                    return default;
                }
                if (authorizationVal == null)
                    throw new ArgumentNullException(nameof(authorizationVal));

                string token = authorizationVal.Value.Value.ToString();
                if (string.IsNullOrEmpty(token))
                    return default;

                string decStr = EncryptionUtility.SymmetricDncrypt(SymmetricEncryptType.Rijndael, token);
                var cols = decStr.Split('|');
                if (cols.Length != 5)
                    return default;

                if (!int.TryParse(cols[0], out int securityId))
                    return default;

                if (!Enum.TryParse(cols[1], out UserType userType))
                    return default;

                if (string.IsNullOrWhiteSpace(cols[2]))
                    return default;

                if (!DateTime.TryParse(cols[3], out DateTime expireTime))
                    return default;

                if (!int.TryParse(cols[4], out int objectId))
                    return default;

                #region 判断缓存里面身份证信息和设备别名是否匹配
                string? cardDevices = memoryCache.Get<string>($"cardDevices:{cols[2]}");
                if (string.IsNullOrEmpty(cardDevices))
                {
                    memoryCache.Set($"cardDevices:{cols[2]}", phoneUuid.Value.Value.ToString());
                    AppDevice? appDevice = appDeviceService.GetAppDeviceByIdCard(cols[2]);
                    if (appDevice == null)
                    {
                        appDevice = new()
                        {
                            UseIdCard = cols[2],
                            Alias = phoneUuid.Value.Value.ToString(),
                            CreateTime = DateTime.Now,
                            LastUpdateTime = DateTime.Now,
                        };
                        appDeviceService.Create(appDevice);
                    }
                    else
                    {
                        appDevice.Alias = phoneUuid.Value.Value.ToString();
                        appDevice.LastUpdateTime = DateTime.Now;
                        appDeviceService.Update(appDevice);
                    }
                }
                else
                {
                    if (cardDevices != phoneUuid.Value.Value.ToString())
                    {
                        #region 激光推送
                        jiguangService.AppointPush(new AppointPushModel()
                        {
                            Title = JiguangConstants.Tips,
                            Message = "你的账号已在别的设备上登录。如果这不是你的操作，你的登录信息可能已泄露，请尽快修改",
                            TargetAlias = ValueUtility.ConvertToList<string>(cardDevices),
                            Extras = new Dictionary<string, object>
                            {
                                { "behavior", Behavior.LogOut }
                            }
                        });
                        #endregion
                        memoryCache.Set($"cardDevices:{cols[2]}", "");
                    }
                }
                #endregion

                _currentUserInfo = new AppUserInfo { SecurityId = securityId, IdCard = cols[2], ExpireTime = expireTime, Type = userType, ObjectId = objectId };

                return (T)_currentUserInfo;
            };
        }
    }
}
